#include "inode.h"
#include <iostream>
#include <cstdlib>
#include <cunistd>
#include <stdint.h>
#include "../utils/util.h"


using namespace std;

namespace PFS
{
    INode::INode()
    {
        parent = NULL;
        access_time = 0;
        modify_time = 0;
        permission = 0;
        create_time = time(NULL);
    }

    INode::INode(const string& name)
    {
        this->name = name;
        this->access_time = 0;
        this->modify_time = 0;
        this->parent = NULL;
        permission = 0;
        create_time = time(NULL);
    }

    INode::INode(const INode &ln)
    {
        name = ln.name;
        access_time = ln.access_time;
        modify_time = ln.modify_time;
        parent = ln.parent;
        permission = ln.permission;
        create_time = ln.create_time;
    }

    virtual INode::~INode()
    {
    }

    void INode::set_access_time(time_t timer)
    {
        access_time = timer;
    }

    time_t INode::get_access_time()
    { return access_time; }

    void INode::set_modify_time(time_t timer)
    {
        modify_time = timer;
    }

    time_t INode::get_modify_time()
    { return modify_time; }

    time_t INode::get_create_time()
    { return create_time; }

    string INode::get_name()
    {
        return name;
    }

    const char* INode::get_name() const
    {
        return name.c_str();
    }

    void INode::set_name(const char* name)
    {
        this->name = string(name);
    }

    bool INode::is_directory()
    { return false; }

    INodeDict* INode::get_parent()
    {
        return parent;
    }

    void INode::set_parent(INodeDict* p)
    {
        parent = p;
    }
    long INode::get_namespace_quota()
    {
        return 0;
    }

    long INode::get_diskspace_quota()
    {
        return 0;
    }

    bool INode::remove_node(bool force_del)
    {
        return_val_if_fail(parent != NULL, false);
        parent->remove_child(this,force_del);
        parent = NULL;
        return true;
    }

    INodeDict::INodeDict()
    {}
    INodeDict::INodeDict(const string& name):INode(name)
    {}

    INodeDict::INodeDict(const INodeDict &ln)
    {
        INodeDict(ln.name);
        this->modify_time = ln.modify_time;
        this->access_time = ln.modify_time;
        this->create_time = ln.create_time;
        children.insert(ln.children.begin(),ln.children.end());
    }

    virtual INodeDict::~INodeDict()
    {
        for(hash_map<const char*, INode*, __gnu_cxx::hash<const char*>, equal_str >::iterator it = children.begin(); it != children.end(); it++)
            delete it->second;
        children.clear();
    }

    virtual bool INodeDict::is_diretory()
    { return true;}

    bool INodeDict::remove_child(const string& name, bool force_del)
    {
        bool del = false;
        map<string,INode*>::iterator it = children.find(name.c_str());
        return_val_if_fail(it != children.end(), false);
        INode* node = it->second;
        if((node->is_directory() && force_del) || !node->is_directory())
            del = true;
        if(del)
        {
            children.erase(it);
            delete node;
            return true;
        }
        else
            return false;
    }


    INode*  INodeDict::replace_child(const string& name, INode* new_node)
    {
        return_val_if_fail(node != NULL, NULL);
        map<string,INode*>::iterator it = children.find(name.c_str());
        if(it != children.end())
        {
            INode* tmp = it->second;
            it->sendcond = new_node;
            return tmp;
        }
        return NULL;
    }

    INode* INodeDict::get_child(const string& name)
    {
        map<string,INode*>::iterator it = children.find(name.c_str());
        if( it != children.end())
            return it->second;
        else
            return NULL;
    }

    void INodeDict::add_child(INode* node)
    {
        return_val_if_fail(node != NULL, NULL);
        string name = node->get_name();
        map<string,INode*>::iterator it = children.find(name.c_str());
        if( it != children.end())
        {
            cout<<"already has "<<node->get_name()<<endl;
            return;
        }
        else
            children[name.c_str()] = node;

    }

    bool INodeDict::exsit_child(const string& name)
    {
        return ( children.count(name.c_str()) == 0 ? false : true );
    }

    INodeFile::INodeFile()
    {
        blocks = new BlockMap();
        this->file_size = 0;
    }

    INodeFile::INodeFile(const string& name)
        :INode(name)
    {
        block = new BlockMap();
        this->file_size = 0;
    }

    INodeFile::~INodeFile()
    {
        if(blocks != NULL)
            delete blocks;
    }

    void INodeFile::add_block(BlockLocate *block)
    {
        uint32_t id= block->get_block_info()->block_id;
        int32_t index = block->get_block_info()->index_of_file;
        blocks->insert(id, block);
        content_block[index] = id;
    }

    bool INodeFile::remove_block(const uint32_t id)
    {
        int32_t index = get_block(id)->get_block_info->index_of_file;
        content_block.erase(index);
        return blocks->remove(id);
    }

    BlockLocate* INodeFile::replace_block(const uint32_t block_id, BlockLocate *new_block)
    {
        int32_t index = get_block(id)->get_block_info->index_of_file;
        content_block.erase(index);
        index = new_block->get_block_info()->index_of_file;
        content_block[index] = block_id;
        return blocks->insert(block_id, new_block, true);
    }

    bool INodeFile::exsit_block(const uint32_t block_id)
    {
        return blocks->exsit(block_id);
    }

    BlockLocate* INodeFile::get_block(const uint32_t block_id)
    {
        return blocks->find(block_id);
    }

    u_int64_t INodeFile::get_file_size() const
    {
        return blocks->get_all_block_bytes();
    }
    
}
